iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
AI & Data

手寫中文字之影像辨識系列 第 16

【第16天】訓練模型-DenseNet201

  • 分享至 

  • xImage
  •  

摘要

  1. DenseNet201

    1.1 來源
    1.2 架構
    1.3 特性

  2. 訓練過程

    2.1 預訓練模型
    2.2 設置Callbacks
    2.3 設置訓練集
    2.4 開始訓練模型
    2.5 儲存模型與紀錄學習曲線

  3. 模型訓練結果

    3.1 學習曲線
    3.2 Accuracy與Loss

  4. 驗證模型準確度

    4.1 程式碼
    4.2 驗證結果


內容

  1. DenseNet201

    1.1 來源

    • 簡介:隨著網路加深,容易遭遇梯度消失的困境。DenseNet受到ResNet與Inception的啟發,藉由增加特徵流通性與降低網路的複雜度,解決此問題,並提高模型訓練效率。
    • 時程:於2016年提出Dense block概念,並於2017年在CVPR發表論文。
    • 論文名稱:Densely Connected Convolutional Networks

    1.2 架構

    • ResNet的啟發:

      • Bottleneck Block
      • ResNet採用Residual直連通路,可利用上一層的輸出(參上圖-A處)
      • 當直Residual直連通路與卷積層合併時,採用Element-wise Addition(殘差值相加),故通道數不變。(參上圖-B處)
    • Inception的啟發:

      • Inception Module
      • Inception將3 * 3卷積拆分成兩個1 * 1與一個3 * 3卷積,減少模型參數量。(參上圖-A處)
      • Inception採用Concatenate進行通道合併,通道數增加。(參上圖-B處)
    • DenseNet:詳細說明請參閱 論文Page3 3.DenseNets

      • 架構表

      • Dense block示意圖
      • 採用直連通道,組成密集連接:可利用前面所有層的輸出。(參Figure1-A處)
      • 將3 * 3卷積拆分成一個1 * 1與一個3 * 3卷積,減少模型參數量。(參Table1-A處)
      • Growth Rate(k)代表Dense Block間每傳遞一次,特徵通道數增加k,有助於減少模型參數。(參Figure1-紅色底線處:k=4)
      • Dense Block間以Transition Layer連接(參Figure1-B處、Table1-B處),主要用來降低特徵數量,篩選出每一層中最有效的特徵。

    1.3 特性

    • DenseNet以Dense block間的特徵傳遞與合併,提高特徵利用效率,降低梯度消失的發生率,有助於模型收斂。
    • Dense Block、Translation layer與Growth Rate的設計,能有效減少模型參數,提高運算效率。
    • 在ImageNet上,DenseNet在保有準確率的情況下,模型的效能甚至超出VGG NET與ResNet。
  2. 訓練過程:

    2.1 預訓練模型

    # IMPORT MODULES
    from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
    from keras.layers import Input, Dense, GlobalAveragePooling2D
    from keras.preprocessing.image import ImageDataGenerator
    from keras.optimizers import Adam
    import matplotlib.pyplot as plt
    from keras.models import Model
    from keras.applications import DenseNet201
    
    # -----------------------------1.客製化模型--------------------------------
    # 載入keras模型(更換輸出圖片尺寸)
    model = Densenet201(include_top=False,
                     weights='imagenet',
                     input_tensor=Input(shape=(80, 80, 3))
                     )
    
    # 定義輸出層
    x = model.output
    x = GlobalAveragePooling2D()(x)
    predictions = Dense(800, activation='softmax')(x)
    model = Model(inputs=model.input, outputs=predictions)
    
    # 編譯模型
    model.compile(optimizer=Adam(lr=0.001),
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    

    2.2 設置Callbacks

    # ---------------------------2.設置callbacks----------------------------
    # 設定earlystop條件
    estop = EarlyStopping(monitor='val_loss', patience=10, mode='min', verbose=1)
    
    # 設定模型儲存條件
    checkpoint = ModelCheckpoint('Densenet201_checkpoint_v2.h5', verbose=1,
                              monitor='val_loss', save_best_only=True,
                              mode='min')
    
    # 設定lr降低條件(0.001 → 0.0002 → 0.00004 → 0.00001)
    reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5,
                               patience=5, mode='min', verbose=1,
                               min_lr=1e-4)
    

    2.3 設置訓練集

    # -----------------------------3.設置資料集--------------------------------
    # 設定ImageDataGenerator參數(路徑、批量、圖片尺寸)
    train_dir = './workout/train/'
    valid_dir = './workout/val/'
    test_dir = './workout/test/'
    batch_size = 64
    target_size = (80, 80)
    
    # 設定批量生成器
    train_datagen = ImageDataGenerator(rescale=1./255, 
                                       rotation_range=20,
                                       width_shift_range=0.2,
                                       height_shift_range=0.2,
                                       shear_range=0.2, 
                                       zoom_range=0.5,
                                       fill_mode="nearest")
    
    val_datagen = ImageDataGenerator(rescale=1./255)
    
    test_datagen = ImageDataGenerator(rescale=1./255)
    
    # 讀取資料集+批量生成器,產生每epoch訓練樣本
    train_generator = train_datagen.flow_from_directory(train_dir,
                                          target_size=target_size,
                                          batch_size=batch_size)
    
    valid_generator = val_datagen.flow_from_directory(valid_dir,
                                          target_size=target_size,
                                          batch_size=batch_size)
    
    test_generator = test_datagen.flow_from_directory(test_dir,
                                          target_size=target_size,
                                          batch_size=batch_size,
                                          shuffle=False)
    

    2.4 重新訓練模型權重

    # -----------------------------4.開始訓練模型------------------------------
    # 重新訓練權重
    history = model.fit_generator(train_generator,
                       epochs=50, verbose=1,
                       steps_per_epoch=train_generator.samples//batch_size,
                       validation_data=valid_generator,
                       validation_steps=valid_generator.samples//batch_size,
                       callbacks=[checkpoint, estop, reduce_lr])
    

    2.5 儲存模型與紀錄學習曲線

    # -----------------------5.儲存模型、紀錄學習曲線------------------------
    # 儲存模型
    model.save('./Densenet201_retrained_v2.h5')
    print('已儲存Densenet201_retrained_v2.h5')
    
    # 畫出acc學習曲線
    acc = history.history['accuracy']
    epochs = range(1, len(acc) + 1)
    val_acc = history.history['val_accuracy']
    plt.plot(epochs, acc, 'bo', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend(loc='lower right')
    plt.grid()
    # 儲存acc學習曲線
    plt.savefig('./acc.png')
    plt.show()
    
    # 畫出loss學習曲線
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    plt.plot(epochs, loss, 'bo', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend(loc='upper right')
    plt.grid()
    # 儲存loss學習曲線
    plt.savefig('loss.png')
    plt.show()
    
  3. 模型訓練結果

    3.1 訓練epochs:25 epochs。

    3.2 耗費時間:2小時22分23秒(8543秒)。

    3.3 學習曲線

    3.4 Accuary與Loss

  4. 驗證準確度

    4.1 程式碼

    # -------------------------6.驗證模型準確度--------------------------
    # 以vali資料夾驗證模型準確度
    test_loss, test_acc = model.evaluate_generator(test_generator,
                                steps=test_generator.samples//batch_size,
                                verbose=1)
    print('test acc:', test_acc)
    print('test loss:', test_loss)
    

    4.2 驗證結果


小結

  1. DensNet準確率不低、參數較少且運算效率佳。若需要在有限的時間下,訓練一個堪用模型Demo,或許是一個不錯的選擇。
  2. 下一章目標是:「介紹第四個預訓練模型InceptionV4,與分享訓練成果」。
    讓我們繼續看下去...

參考資料

  1. Densely Connected Convolutional Networks
  2. 深度学习 机器视觉 经典卷积神经网络 Tensorflow2.0 keras.applications

上一篇
【第15天】訓練模型-ResNet152V2
下一篇
【第17天】訓練模型-InceptionV4
系列文
手寫中文字之影像辨識31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言